home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / mandel / mandel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  23.6 KB  |  899 lines

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <values.h>
  4. #include <X11/StringDefs.h>
  5. #include <X11/Intrinsic.h>
  6. #include <Xm/Xm.h>
  7. #include <Xm/DrawingA.h>
  8. #include <X11/Xutil.h>
  9. #include <X11/cursorfont.h>
  10. #include "defs.h"
  11. #include "funcs.h"
  12. #include "icon.h"
  13. #include "macro.h"
  14.  
  15. typedef struct points_t {
  16.     XPoint data[MAXCOLOR][MAXPOINTS];
  17.     int npoints[MAXCOLOR];
  18.     } points_t;
  19.  
  20. static void SetCursorColors(image_data_t *data);
  21. static void UsageMessage(image_data_t *data);
  22. static void NewColormap(image_data_t *data, int color);
  23. static void FlipRotate(image_data_t *data);
  24. static void KeyPressFunc(Widget w, image_data_t *data, XEvent *event);
  25. static GC CreateXorGC(Widget w);
  26. static void StartRubberBand(Widget w, image_data_t *data, XEvent *event);
  27. static void SetupCorners(XPoint *corners, image_data_t *data);
  28. static void TrackRubberBand(Widget w, image_data_t *data, XEvent *event);
  29. static void EndRubberBand(Widget w, image_data_t *data, XEvent *event);
  30. static void InitData(Widget toplevel, Widget w, image_data_t *data);
  31. static void HalfIntensity(unsigned short *color);
  32. static void SetupStripeCmap(image_data_t *data, XColor *colors);
  33. static void SetupRainbow(int ncells, XColor *colors);
  34. static void HLSToRGB(int *hue_light_sat, int *rgb);
  35. static double HueValue(double n1, double n2, double hue);
  36. static void Redisplay(Widget w, image_data_t *data,
  37.     XmDrawingAreaCallbackStruct *call_data);
  38. static void Resize(Widget w, image_data_t *data, caddr_t call_data);
  39. static Boolean RotateWorkProc(image_data_t *data);
  40. static void SetupMonoCmap(image_data_t *data, XColor *colors, int i_inc);
  41. static void NoGreenCmap(image_data_t *data, XColor *colors);
  42. static void NewRotateJumpCount(image_data_t *data, int count);
  43.  
  44. static points_t *Points;
  45.  
  46. static XtResource Resources [] = {
  47.     {"width", "Width", XtRInt, sizeof(Dimension), XtOffset(image_data_ptr_t,
  48.         width), XtRString, "200"},
  49.     {"height", "Height", XtRInt, sizeof(Dimension),
  50.         XtOffset(image_data_ptr_t, height), XtRString, "200"},
  51.     {"mdepth", "MDepth", XtRInt, sizeof(int), XtOffset(image_data_ptr_t,
  52.         M), XtRString, "1000"},
  53.     {"kvalue", "KValue", XtRInt, sizeof(int), XtOffset(image_data_ptr_t,
  54.         K), XtRString, "128"},
  55.     {"p_min", "P_min", XtRFloat, sizeof(float), XtOffset(image_data_ptr_t,
  56.         ip_min), XtRString, "-2.25"},
  57.     {"p_max", "P_max", XtRFloat, sizeof(float), XtOffset(image_data_ptr_t,
  58.         ip_max), XtRString, "0.75"},
  59.     {"q_min", "Q_min", XtRFloat, sizeof(float), XtOffset(image_data_ptr_t,
  60.         iq_min), XtRString, "-1.5"},
  61.     {"q_max", "Q_max", XtRFloat, sizeof(float), XtOffset(image_data_ptr_t,
  62.         iq_max), XtRString, "1.5"}};
  63.  
  64. int
  65. main(
  66.     int argc,
  67.     char *argv[])
  68. {
  69.     Widget toplevel, area;
  70.     image_data_t data;
  71.     int n;
  72.     Arg wargs[4];
  73.  
  74.     toplevel = XtInitialize(argv[0], "Mandel", (char **)0, 0, &argc, argv);
  75.     XtGetApplicationResources(toplevel, &data, Resources,
  76.         XtNumber(Resources), (char **)0, 0);
  77.     n = 0;
  78.     XtSetArg(wargs[n], XmNminAspectX, 1); ++n;
  79.     XtSetArg(wargs[n], XmNminAspectY, 1); ++n;
  80.     XtSetArg(wargs[n], XmNmaxAspectX, 1); ++n;
  81.     XtSetArg(wargs[n], XmNmaxAspectY, 1); ++n;
  82.     XtSetValues(toplevel, wargs, n);
  83.     area = XtCreateManagedWidget("area", xmDrawingAreaWidgetClass, toplevel,
  84.         (Arg *)NULL, 0);
  85.     n = 0;
  86.     XtSetArg(wargs[n], XtNwidth, 200); ++n;
  87.     XtSetArg(wargs[n], XtNheight, 200); ++n;
  88.     XtSetValues(toplevel, wargs, n);
  89.     InitData(toplevel, area, &data);
  90.     UsageMessage(&data);
  91.     XtAddCallback(area, XmNexposeCallback, Redisplay, &data);
  92.     XtAddCallback(area, XmNresizeCallback, Resize, &data);
  93.     XtAddEventHandler(area, ButtonPressMask, FALSE, StartRubberBand, &data);
  94.     XtAddEventHandler(area, ButtonMotionMask, FALSE, TrackRubberBand,
  95.         &data);
  96.     XtAddEventHandler(area, ButtonReleaseMask, FALSE, EndRubberBand, &data);
  97.     XtAddEventHandler(area, KeyPressMask, FALSE, KeyPressFunc, &data);
  98.     XtRealizeWidget(toplevel);
  99.     data.band_cursor = XCreateFontCursor(XtDisplay(area), XC_hand2);
  100.     XGrabButton(XtDisplay(area), AnyButton, AnyModifier, XtWindow(area),
  101.         TRUE, ButtonPressMask | ButtonMotionMask | ButtonReleaseMask,
  102.         GrabModeAsync, GrabModeAsync, XtWindow(area),
  103.         data.band_cursor);
  104.     data.rubber_band.gc = CreateXorGC(area);
  105.     Points = (points_t *)ALLOCATE_LOCAL(sizeof(points_t));
  106.     XDefineCursor(XtDisplay(area), XtWindow(area), data.normal_cursor);
  107.     n = 0;
  108.     XtSetArg(wargs[n], XmNiconPixmap,
  109.         XCreatePixmapFromBitmapData(XtDisplay(area), XtWindow(area),
  110.         noname_bits, noname_width, noname_height, 1, 0, 1)); ++n;
  111.     XtSetValues(toplevel, wargs, n);
  112.     Resize(area, &data, (caddr_t)0);
  113.     XtMainLoop();
  114.     DEALLOCATE_LOCAL((char *)Points);
  115. }
  116.  
  117. static void
  118. SetCursorColors(
  119.     image_data_t *data)
  120. {
  121.     unsigned int i, index;
  122.     double red, green, blue, val, max_val;
  123.     XColor bgcolor, fgcolor;
  124.  
  125.     index = 0;
  126.     max_val = 0.0;
  127.     for (i = 0; i < data->max_color; ++i)
  128.     {
  129.         red = data->colors[i].red;
  130.         green = data->colors[i].green;
  131.         blue = data->colors[i].blue;
  132.         val = red * red + green * green + blue * blue;
  133.         if (val > max_val)
  134.         {
  135.             max_val = val;
  136.             index = i;
  137.         }
  138.     }
  139.     bgcolor = data->colors[index];
  140.     fgcolor = data->colors[0];
  141.     XRecolorCursor(XtDisplay(data->area), data->normal_cursor, &fgcolor,
  142.         &bgcolor);
  143.     XRecolorCursor(XtDisplay(data->area), data->clock_cursor, &fgcolor,
  144.         &bgcolor);
  145.     XRecolorCursor(XtDisplay(data->area), data->band_cursor, &fgcolor,
  146.         &bgcolor);
  147.     XFlush(XtDisplay(data->area));
  148. }
  149.  
  150. static void
  151. UsageMessage(
  152.     image_data_t *data)
  153. {
  154.     printf("\n\t\tMandelbrot Generator\n\n");
  155.     printf("Select area to be investigated with mouse\n");
  156.     printf("Keyboard:\n");
  157.     printf("\t 'r' - use red colormap\n");
  158.     printf("\t 'g' - use green colormap\n");
  159.     printf("\t 'b' - use blue colormap\n");
  160.     printf("\t 'm' - use mono colormap\n");
  161.     printf("\t 'c' - use colorwheel colormap [default]\n");
  162.     printf("\t 'n' - use default colormap [cannot be rotated]\n");
  163.     printf("\t 's' - use stripe colorwheel colormap\n");
  164.     printf("\t 'a' - use non-green colormap\n");
  165.     printf("\t 'R' - toggle colormap rotation\n");
  166.     printf("\t '1'..'9' - change colormap rotation speed\n");
  167.     printf("\t 'x' - reverse colormap rotate direction\n");
  168.     printf("\t 'd' - dump current fractal to file \"mandel.xwd\"\n");
  169.     printf(
  170.         "\t space - double K value (depth of calculation) [default %d]\n",
  171.         128);
  172.     printf("\t 'i' - toggle between generation algorithms\n");
  173.     printf("\t 'q' - quit program\n");
  174. }
  175.  
  176. static void
  177. NewColormap(
  178.     image_data_t *data,
  179.     int color)
  180. {
  181.     data->cm_current = color;
  182.     XSetWindowColormap(XtDisplay(data->area), XtWindow(data->toplevel),
  183.         data->cmaps[data->cm_current]);
  184.     if (data->run_work_proc && data->cm_current == CM_DEFAULT)
  185.     {
  186.         printf("Cannot rotate the default colormap Bucko!\n");
  187.         printf("Switching to rainbow.\n");
  188.         NewColormap(data, CM_RAINBOW);
  189.     }
  190.     else
  191.     {
  192.         XQueryColors(XtDisplay(data->area),
  193.             data->cmaps[data->cm_current], data->colors,
  194.             data->max_color);
  195.         SetCursorColors(data);
  196.     }
  197. }
  198.  
  199. static void
  200. FlipRotate(
  201.     image_data_t *data)
  202. {
  203.     data->run_work_proc = ! data->run_work_proc;
  204.     if (data->run_work_proc)
  205.     {
  206.         if (data->cm_current == CM_DEFAULT)
  207.         {
  208.             printf("Cannot rotate the default colormap Bucko!\n");
  209.             printf("Switching to rainbow.\n");
  210.             NewColormap(data, CM_RAINBOW);
  211.         }
  212.         XQueryColors(XtDisplay(data->area),
  213.             data->cmaps[data->cm_current], data->colors,
  214.             data->max_color);
  215.         data->work_proc = XtAddWorkProc(RotateWorkProc, data);
  216.     }
  217.     else
  218.         XtRemoveWorkProc(data->work_proc);
  219. }
  220.  
  221. static void
  222. KeyPressFunc(
  223.     Widget w,
  224.     image_data_t *data,
  225.     XEvent *event)
  226. {
  227.     XKeyEvent *keyevent = (XKeyEvent *)event;
  228.     unsigned char key;
  229.     FILE *fp;
  230.  
  231.     if (XLookupString(keyevent, (char *)&key, sizeof(key), (KeySym *)0,
  232.         (XComposeStatus *) 0) > 0)
  233.         switch (key)
  234.         {
  235.             case '1' :
  236.             case '2' :
  237.             case '3' :
  238.             case '4' :
  239.             case '5' :
  240.             case '6' :
  241.             case '7' :
  242.             case '8' :
  243.             case '9' :
  244.             NewRotateJumpCount(data, key - '1');
  245.             break;
  246.             case ' ' :
  247.             data->K += data->K;
  248.             printf("K=%d\n", data->K);
  249.             fflush(stdout);
  250.             (*data->create_image)(w, data);
  251.             break;
  252.             case 'n' :
  253.             NewColormap(data, CM_DEFAULT);
  254.             break;
  255.             case 'r' :
  256.             NewColormap(data, CM_RED);
  257.             break;
  258.             case 'g' :
  259.             NewColormap(data, CM_GREEN);
  260.             break;
  261.             case 'b' :
  262.             NewColormap(data, CM_BLUE);
  263.             break;
  264.             case 'c' :
  265.             NewColormap(data, CM_RAINBOW);
  266.             break;
  267.             case 'm' :
  268.             NewColormap(data, CM_MONO);
  269.             break;
  270.             case 's' :
  271.             NewColormap(data, CM_STRIPE);
  272.             break;
  273.             case 'a' :
  274.             NewColormap(data, CM_NOGREEN);
  275.             break;
  276.             case 'R' :
  277.             FlipRotate(data);
  278.             break;
  279.             case 'x' :
  280.             data->rotate_forward = ! data->rotate_forward;
  281.             break;
  282.             case 'd' :
  283.             if ((fp = fopen("mandel.xwd", "w")) == NULL)
  284.             {
  285.                 printf("I canna' open mandel.xwd, Captain!\n");
  286.                 fflush(stdout);
  287.                 return;
  288.             }
  289.             Window_Dump(data->toplevel, XtWindow(data->toplevel),
  290.                 fp);
  291.             fclose(fp);
  292.             break;
  293.             case 'i' :
  294.             if (data->create_image == CreateImage)
  295.             {
  296.                 printf("Calculate each dot.\n");
  297.                 data->create_image = CreateImageOld;
  298.             }
  299.             else
  300.             {
  301.                 printf("Fill rectangle areas of same color.\n");
  302.                 data->create_image = CreateImage;
  303.             }
  304.             break;
  305.             case 'q' :
  306.             exit(0);
  307.             default :
  308.             printf("I don't do %c\n", key);
  309.             fflush(stdout);
  310.         }
  311. }
  312.  
  313. static GC
  314. CreateXorGC(
  315.     Widget w)
  316. {
  317.     XGCValues values;
  318.     GC gc;
  319.     Arg wargs[2];
  320.  
  321.     XtSetArg(wargs[0], XtNforeground, &values.foreground);
  322.     XtSetArg(wargs[1], XtNbackground, &values.background);
  323.     XtGetValues,(w, wargs, 2);
  324.     values.foreground = values.foreground ^ values.background;
  325. /*    values.line_style = LineOnOffDash; */
  326.     values.line_style = LineSolid;
  327.     values.function = GXxor;
  328.     return XtGetGC(w, GCForeground | GCBackground | GCFunction |
  329.         GCLineStyle, &values);
  330. }
  331.  
  332. static void
  333. StartRubberBand(
  334.     Widget w,
  335.     image_data_t *data,
  336.     XEvent *event)
  337. {
  338.     XPoint corners[5];
  339.  
  340.     data->rubber_band.last_x = data->rubber_band.start_x = event->xbutton.x;
  341.     data->rubber_band.last_y = data->rubber_band.start_y = event->xbutton.y;
  342.     SetupCorners(corners, data);
  343.     XDrawLines(XtDisplay(w), XtWindow(w), data->rubber_band.gc,
  344.         corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  345. }
  346.  
  347. static void
  348. SetupCorners(
  349.     XPoint *corners,
  350.     image_data_t *data)
  351. {
  352.     corners[0].x = data->rubber_band.start_x;
  353.     corners[0].y = data->rubber_band.start_y;
  354.     corners[1].x = data->rubber_band.start_x;
  355.     corners[1].y = data->rubber_band.last_y;
  356.     corners[2].x = data->rubber_band.last_x;
  357.     corners[2].y = data->rubber_band.last_y;
  358.     corners[3].x = data->rubber_band.last_x;
  359.     corners[3].y = data->rubber_band.start_y;
  360.     corners[4] = corners[0];
  361. }
  362.  
  363. static void
  364. TrackRubberBand(
  365.     Widget w,
  366.     image_data_t *data,
  367.     XEvent *event)
  368. {
  369.     XPoint corners[5];
  370.     int xdiff, ydiff, diff;
  371.  
  372.     SetupCorners(corners, data);
  373.     XDrawLines(XtDisplay(w), XtWindow(w), data->rubber_band.gc,
  374.         corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  375.     ydiff = event->xbutton.y - data->rubber_band.start_y;
  376.     xdiff = event->xbutton.x - data->rubber_band.start_x;
  377.     if (xdiff > ydiff)
  378.         diff = ydiff;
  379.     else
  380.         diff = xdiff;
  381.     data->rubber_band.last_x = data->rubber_band.start_x + diff;
  382.     data->rubber_band.last_y = data->rubber_band.start_y + diff;
  383.     if (data->rubber_band.last_y < data->rubber_band.start_y ||
  384.         data->rubber_band.last_x < data->rubber_band.start_x)
  385.     {
  386.         data->rubber_band.last_y = data->rubber_band.start_y;
  387.         data->rubber_band.last_x = data->rubber_band.start_x;
  388.     }
  389.     SetupCorners(corners, data);
  390.     XDrawLines(XtDisplay(w), XtWindow(w), data->rubber_band.gc,
  391.         corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  392. }
  393.  
  394. static void
  395. EndRubberBand(
  396.     Widget w,
  397.     image_data_t *data,
  398.     XEvent *event)
  399. {
  400.     XPoint corners[5];
  401.     XPoint top, bot;
  402.     double delta, diff;
  403.  
  404.     SetupCorners(corners, data);
  405.     XDrawLines(XtDisplay(w), XtWindow(w), data->rubber_band.gc,
  406.         corners, sizeof(corners) / sizeof(corners[0]), CoordModeOrigin);
  407. /*    printf("width=%d height=%d start_x=%d start_y=%d last_x=%d last_y=%d\n",
  408.         data->width, data->height,
  409.         data->rubber_band.start_x,
  410.         data->rubber_band.start_y,
  411.         data->rubber_band.last_x,
  412.         data->rubber_band.last_y);
  413.     fflush(stdout); */
  414.     if (data->rubber_band.start_x >= data->rubber_band.last_x ||
  415.         data->rubber_band.start_y >= data->rubber_band.last_y)
  416.         return;
  417.     top.x = data->rubber_band.start_x;
  418.     bot.x = data->rubber_band.last_x;
  419.     top.y = data->rubber_band.start_y;
  420.     bot.y = data->rubber_band.last_y;
  421.     diff = data->q_max - data->q_min;
  422.     delta = (double)top.y / (double)data->height;
  423.     data->q_min += diff * delta;
  424.     delta = (double)(data->height - bot.y) / (double)data->height;
  425.     data->q_max -= diff * delta;
  426.     diff = data->p_max - data->p_min;
  427.     delta = (double)top.x / (double)data->width;
  428.     data->p_min += diff * delta;
  429.     delta = (double)(data->width - bot.x) / (double)data->width;
  430.     data->p_max -= diff * delta;
  431.     printf("q_min=%2.12f q_max=%2.12f\np_min=%2.12f p_max=%2.12f\n\n",
  432.         data->q_min, data->q_max, data->p_min, data->p_max);
  433.     fflush(stdout);
  434.     (*data->create_image)(w, data);
  435. }
  436.  
  437. static void
  438. InitData(
  439.     Widget toplevel,
  440.     Widget w,
  441.     image_data_t *data)
  442. {
  443.     int n, i, i_inc, j, nitems, biggest_colormap;
  444.     Arg wargs[32];
  445.     XColor *colors;
  446.     XVisualInfo *visual_list, visual_template;
  447.  
  448.     n = 0;
  449.     XtSetArg(wargs[n], XtNwidth, &data->width); ++n;
  450.     XtSetArg(wargs[n], XtNheight, &data->height); ++n;
  451.     XtGetValues(w, wargs, n);
  452.     data->area = w;
  453.     data->max_color = XDisplayCells(XtDisplay(w),
  454.         XDefaultScreen(XtDisplay(w)));
  455.     data->gc = XCreateGC(XtDisplay(w), DefaultRootWindow(XtDisplay(w)),
  456.         0, (XGCValues *)0);
  457.     data->pix = 0;
  458.     data->p_min = data->ip_min;
  459.     data->p_max = data->ip_max;
  460.     data->q_min = data->iq_min;
  461.     data->q_max = data->iq_max;
  462.  
  463.     data->toplevel = toplevel;
  464.     data->cm_current = CM_RAINBOW;
  465.     visual_template.class = PseudoColor;
  466.     visual_list = XGetVisualInfo(XtDisplay(w), VisualClassMask,
  467.         &visual_template, &nitems);
  468.     if (! visual_list)
  469.     {
  470.         fprintf(stderr, "Unable to find PseudoColor visual!\n");
  471.         exit(1);
  472.     }
  473.     biggest_colormap = 0;
  474.     data->visual = (Visual *)NULL;
  475.     for (i = 0; i < nitems; ++i)
  476.         if (biggest_colormap < visual_list[i].colormap_size &&
  477.             visual_list[i].colormap_size < MAXCOLOR)
  478.         {
  479.             biggest_colormap = visual_list[i].colormap_size;
  480.             data->visual = visual_list[i].visual;
  481.         }
  482.     if (! data->visual)
  483.     {
  484.         fprintf(stderr,
  485.             "Unable to find visual with colormap > 0 and < %d!\n",
  486.             MAXCOLOR);
  487.         exit(1);
  488.     }
  489.     for (i = 0; i < MAX_CMAPS - 1; ++i)
  490.         data->cmaps[i] = XCreateColormap(XtDisplay(w),
  491.             DefaultRootWindow(XtDisplay(w)), data->visual, AllocAll);
  492.     colors = (XColor *)ALLOCATE_LOCAL(data->max_color * sizeof(XColor));
  493.     i_inc = 65536 / data->max_color * 2;
  494.     data->cmaps[CM_DEFAULT] = DefaultColormap(XtDisplay(w),
  495.         DefaultScreen(XtDisplay(w)));
  496.     SETUP_COLOR(w, red, green, blue, colors, data, i_inc, CM_RED);
  497.     SETUP_COLOR(w, green, blue, red, colors, data, i_inc, CM_GREEN);
  498.     SETUP_COLOR(w, blue, green, red, colors, data, i_inc, CM_BLUE);
  499.     SetupRainbow(data->max_color, colors);
  500.     XStoreColors(XtDisplay(w), data->cmaps[CM_RAINBOW], colors,
  501.         data->max_color);
  502.     SetupMonoCmap(data, colors, i_inc);
  503.     SetupStripeCmap(data, colors);
  504.     XStoreColors(XtDisplay(w), data->cmaps[CM_STRIPE], colors,
  505.         data->max_color);
  506.     NoGreenCmap(data, colors);
  507.     DEALLOCATE_LOCAL((char *)colors);
  508.     data->run_work_proc = FALSE;
  509.     data->rotate_forward = TRUE;
  510.     data->rotate_jump_count = 1;
  511.     data->colors = (XColor *)malloc(data->max_color * sizeof(XColor));
  512.     for (i = 0; i < data->max_color; ++i)
  513.         data->colors[i].pixel = i;
  514.     data->normal_cursor = XCreateFontCursor(XtDisplay(w), XC_crosshair);
  515.     data->clock_cursor = XCreateFontCursor(XtDisplay(w), XC_watch);
  516.     data->create_image = CreateImage;
  517. }
  518.  
  519. static void
  520. HalfIntensity(
  521.     unsigned short *color)
  522. {
  523.     *color /= 1.5;
  524. }
  525.  
  526. static void
  527. SetupStripeCmap(
  528.     image_data_t *data,
  529.     XColor *colors)
  530. {
  531.     int i, half;
  532.  
  533.     SetupRainbow(data->max_color, colors);
  534.     for (i = 1; i < data->max_color; i += 3)
  535.     {
  536.         HalfIntensity(&colors[i].red);
  537.         HalfIntensity(&colors[i].green);
  538.         HalfIntensity(&colors[i].blue);
  539.     }
  540. }
  541.  
  542. static void
  543. SetupRainbow(
  544.     int ncells,
  545.     XColor *colors)
  546. {
  547.     int i;
  548.     int hls[3], rgb[3];
  549.  
  550.     hls[1] = 500;
  551.     hls[2] = 1000;
  552.     colors[0].red = 0;
  553.     colors[0].green = 0;
  554.     colors[0].blue = 0;
  555.     colors[0].flags = DoRed | DoGreen | DoBlue;
  556.     for (i = 1; i < ncells; ++i)
  557.     {
  558.         hls[0] = 3600 * i / ncells;
  559.         HLSToRGB(hls, rgb);
  560.         colors[i].red = rgb[0];
  561.         colors[i].green = rgb[1];
  562.         colors[i].blue = rgb[2];
  563.         colors[i].flags = DoRed | DoGreen | DoBlue;
  564.     }
  565. }
  566.  
  567. /*
  568.  * NAME: hls2rgb() from foley and van dam, fundamentals of interactive ...
  569.  *        page 619
  570.  *
  571.  * PURPOSE: Convert hls[0..3600][0..1000][0..1000] space to rgb space
  572.  *    That is the Hue, Lightness, Saturation color model.
  573.  *    Which is two cones, base to base, the bottom tip is black, the
  574.  *    top tip is white, the middle (bases) around the outside is a color
  575.  *    wheel.  The axis of this solid is Lightness.  Hue is the angular
  576.  *    measure around the cones, and the saturation is the radius from the
  577.  *    axis towards the surface of the cones.
  578.  */
  579. static void
  580. HLSToRGB(
  581.     int *hue_light_sat,
  582.     int *rgb)                                    /* Each in range [0..65535] */
  583. {
  584.     double r, g, b, h, l, s;
  585.     double m1, m2;
  586.  
  587.     h = (double) hue_light_sat[0] / 10.0;
  588.     l = (double) hue_light_sat[1] / 1000.0;
  589.     s = (double) hue_light_sat[2] / 1000.0;
  590.  
  591.     if ( l < 0.5 )
  592.     {
  593.         m2 = l * ( 1.0 + s );
  594.     }
  595.     else
  596.     {
  597.         m2 = l + s - (l * s);
  598.     }
  599.     m1 = (2.0 * l) - m2;
  600.     if ((s + 1.0) == 1.0 )
  601.     {
  602.         if ( (h + 1.0) < 1.0 )
  603.         {
  604.             r = g = b = l;
  605.         }
  606.         else
  607.         {
  608.             r = g = b = 0.0;
  609.         }
  610.     }
  611.     else
  612.     {
  613.         r = HueValue( m1, m2, h + 120.0 );
  614.         g = HueValue( m1, m2, h );
  615.         b = HueValue( m1, m2, h - 120.0 );
  616.     }
  617.     rgb[0] = 65535.0 * r;
  618.     rgb[1] = 65535.0 * g;
  619.     rgb[2] = 65535.0 * b;
  620.     if ( rgb[0] > 65535 )
  621.         rgb[0] = 65535;
  622.     else if ( rgb[0] < 0 )
  623.         rgb[0] = 0;
  624.  
  625.     if ( rgb[1] > 65535 )
  626.         rgb[1] = 65535;
  627.     else if ( rgb[1] < 0 )
  628.         rgb[1] = 0;
  629.  
  630.     if ( rgb[2] > 65535 )
  631.         rgb[2] = 65535;
  632.     else if ( rgb[2] < 0 )
  633.         rgb[2] = 0;
  634. }
  635.  
  636. static double
  637. HueValue(
  638.     double n1,
  639.     double n2,
  640.     double hue)
  641. {
  642.     if ( hue > 360.0 )
  643.         hue -= 360.0;
  644.     if ( hue < 0.0 )
  645.         hue += 360.0;
  646.     if ( hue < 60.0 )
  647.         return n1 + ((n2 - n1) * hue / 60.0);
  648.     else if ( hue < 180.0 )
  649.         return n2;
  650.     else if ( hue < 240.0 )
  651.         return n1 + ((n2 - n1) * (240.0 - hue) / 60.0);
  652.     else
  653.         return n1;
  654. }
  655.  
  656. void
  657. InitBuffer(
  658.     image_data_t *data)
  659. {
  660.     int i;
  661.  
  662.     if (data->max_color > MAXCOLOR)
  663.         XtError("This display has too many colors (I'm sure!!)");
  664.     for (i = 0 ; i < MAXCOLOR; ++i)
  665.         Points->npoints[i] = 0;
  666. }
  667.  
  668. void
  669. BufferRectangle(
  670.     image_data_t *data,
  671.     int color,
  672.     int x0,
  673.     int y0,
  674.     int x1,
  675.     int y1)
  676. {
  677.     Widget w = data->area;
  678.     int width = x1 - x0;
  679.     int height = y1 - y0;
  680.  
  681.     if (width <= 0 || height <= 0)
  682.         return;
  683.     XSetForeground(XtDisplay(w), data->gc, color);
  684.     if (XtIsRealized(w))
  685.         XFillRectangle(XtDisplay(w), XtWindow(w), data->gc, x0, y0,
  686.             width, height);
  687.     XFillRectangle(XtDisplay(w), data->pix, data->gc, x0, y0, width,
  688.         height);
  689. }
  690.  
  691. void
  692. BufferPoint(
  693.     Widget w,
  694.     image_data_t *data,
  695.     int color,
  696.     int x,
  697.     int y)
  698. {
  699.     if (Points->npoints[color] == MAXPOINTS - 1)
  700.     {
  701.         XSetForeground(XtDisplay(w), data->gc, color);
  702.         if (XtIsRealized(w))
  703.             XDrawPoints(XtDisplay(w), XtWindow(w), data->gc,
  704.                 Points->data[color], Points->npoints[color],
  705.                 CoordModeOrigin);
  706.         XDrawPoints(XtDisplay(w), data->pix, data->gc,
  707.             Points->data[color], Points->npoints[color],
  708.             CoordModeOrigin);
  709.         Points->npoints[color] = 0;
  710.     }
  711.     Points->data[color][Points->npoints[color]].x = x;
  712.     Points->data[color][Points->npoints[color]].y = y;
  713.     ++Points->npoints[color];
  714. }
  715.  
  716. void
  717. FlushBuffer(
  718.     Widget w,
  719.     image_data_t *data)
  720. {
  721.     int color;
  722.  
  723.     for (color = 0; color < data->max_color; ++color)
  724.         if (Points->npoints[color])
  725.         {
  726.             XSetForeground(XtDisplay(w), data->gc, color);
  727.             if (XtIsRealized(w))
  728.                 XDrawPoints(XtDisplay(w), XtWindow(w), data->gc,
  729.                     Points->data[color], Points->npoints[color],
  730.                     CoordModeOrigin);
  731.             XDrawPoints(XtDisplay(w), data->pix, data->gc,
  732.                 Points->data[color], Points->npoints[color],
  733.                 CoordModeOrigin);
  734.             Points->npoints[color] = 0;
  735.         }
  736. }
  737.  
  738. static void
  739. Redisplay(
  740.     Widget w,
  741.     image_data_t *data,
  742.     XmDrawingAreaCallbackStruct *call_data)
  743. {
  744.     XExposeEvent *event = (XExposeEvent *)call_data->event;
  745.  
  746.     XCopyArea(XtDisplay(w), data->pix, XtWindow(w), data->gc, event->x,
  747.         event->y, event->width, event->height, event->x, event->y);
  748.     NewColormap(data, data->cm_current);
  749. }
  750.  
  751. static void
  752. Resize(
  753.     Widget w,
  754.     image_data_t *data,
  755.     caddr_t call_data)
  756. {
  757.     int n;
  758.     Arg wargs[32];
  759.  
  760.     n = 0;
  761.     XtSetArg(wargs[n], XtNwidth, &data->width); ++n;
  762.     XtSetArg(wargs[n], XtNheight, &data->height); ++n;
  763.     XtGetValues(w, wargs, n);
  764.     if (XtIsRealized(w))
  765.         XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE);
  766.     if (data->pix)
  767.         XFreePixmap(XtDisplay(w), data->pix);
  768.     data->pix = XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)),
  769.         data->width, data->height, DefaultDepthOfScreen(XtScreen(w)));
  770.     XSetForeground(XtDisplay(w), data->gc, BlackPixelOfScreen(XtScreen(w)));
  771.     XFillRectangle(XtDisplay(w), data->pix, data->gc, 0, 0, data->width,
  772.         data->height);
  773.     (*data->create_image)(w, data);
  774.     NewColormap(data, data->cm_current);
  775. }
  776.  
  777. static Boolean
  778. RotateWorkProc(
  779.     image_data_t *data)
  780. {
  781.     int i, last, count;
  782.     unsigned long tmppixel;
  783.  
  784.     if (! XtIsRealized(data->area))
  785.         return FALSE;
  786.     for (count = 0; count < data->rotate_jump_count; ++count)
  787.     {
  788.         if (data->rotate_forward)
  789.         {
  790.             tmppixel = data->colors[1].pixel;
  791.             for (i = 2; i < data->max_color; ++i)
  792.                 data->colors[i - 1].pixel =
  793.                     data->colors[i].pixel;
  794.             data->colors[data->max_color - 1].pixel = tmppixel;
  795.         }
  796.         else
  797.         {
  798.             last = data->max_color - 1;
  799.             tmppixel = data->colors[last].pixel;
  800.             for (i = data->max_color - 1; i >= 2; --i)
  801.                         {
  802.                                 unsigned long   ptmp;
  803.  
  804.                                 ptmp = data->colors[i - 1].pixel;
  805.                                 data->colors[i].pixel = ptmp;
  806.                         }
  807.             data->colors[1].pixel = tmppixel;
  808.         }
  809.     }
  810.     XStoreColors(XtDisplay(data->toplevel), data->cmaps[data->cm_current],
  811.         data->colors, data->max_color);
  812.     SetCursorColors(data);
  813.  
  814.     return FALSE;
  815. }
  816.  
  817. static void
  818. SetupMonoCmap(
  819.     image_data_t *data,
  820.     XColor *colors,
  821.     int i_inc)
  822. {
  823.     int i, j;
  824.     Widget w = data->area;
  825.  
  826.     for (i = 0, j = 0; j < data->max_color / 2; ++j, i += i_inc)
  827.     {
  828.         colors[j].pixel = j;
  829.         colors[j].red = i < 65536 ? i : 65535;
  830.         colors[j].green = i < 65536 ? i : 65535;
  831.         colors[j].blue = i < 65536 ? i : 65535;
  832.         colors[j].flags = DoRed | DoGreen | DoBlue;
  833.     }
  834.     for (i = 65535, j = data->max_color / 2; j < data->max_color; ++j,
  835.         i -= i_inc)
  836.     {
  837.         colors[j].pixel = j;
  838.         colors[j].red = i;
  839.         colors[j].green = i;
  840.         colors[j].blue = i;
  841.         colors[j].flags = DoRed | DoGreen | DoBlue;
  842.     }
  843.     XStoreColors(XtDisplay(w), data->cmaps[CM_MONO], colors,
  844.         data->max_color);
  845. }
  846.  
  847. static void
  848. NoGreenCmap(
  849.     image_data_t *data,
  850.     XColor *colors)
  851. {
  852.     int step, i, leg, j;
  853.  
  854.     step = data->max_color / 3;
  855.     leg = step;
  856.     colors[0].red = 0;
  857.     colors[0].green = 0;
  858.     colors[0].blue = 0;
  859.     colors[0].flags = DoRed | DoGreen | DoBlue;
  860.     for (i = 1; i < leg; ++i)
  861.     {
  862.         colors[i].pixel = i;
  863.         colors[i].red = fabs(65535 - (double)i / step * 65535.0);
  864.         colors[i].blue = (double)i / step * 65535.0;
  865.         colors[i].green = 0;
  866.         colors[i].flags = DoRed | DoGreen | DoBlue;
  867.     }
  868.     for (j = 0, i = leg, leg += step; i < leg; ++i, ++j)
  869.     {
  870.         colors[i].pixel = i;
  871.         colors[i].red = (double)j / step * 65535.0;
  872.         colors[i].blue = 65535;
  873.         colors[i].green = colors[i].red;
  874.         colors[i].flags = DoRed | DoGreen | DoBlue;
  875.     }
  876.     for (j = 0, i = leg, leg += step; i < leg; ++i, ++j)
  877.     {
  878.         colors[i].pixel = i;
  879.         colors[i].red = 65535;
  880.         colors[i].blue = fabs(65535 - (double)j / step * 65535.0);
  881.         colors[i].green = colors[i].blue;
  882.         colors[i].flags = DoRed | DoGreen | DoBlue;
  883.     }
  884.     XStoreColors(XtDisplay(data->area), data->cmaps[CM_NOGREEN], colors,
  885.         data->max_color);
  886. }
  887.  
  888. static void
  889. NewRotateJumpCount(
  890.     image_data_t *data,
  891.     int count)
  892. {
  893.     if (count <= 0)
  894.         count = 1;
  895.     else
  896.         count *= (double)data->max_color / 50.0;
  897.     data->rotate_jump_count = count;
  898. }
  899.